/* Copyright (c) 2004-2024 Peigen.info. All rights reserved. */

package info.peigen.hotpot.business.customer.core.domain.action;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.lang.Validator;
import cn.hutool.core.util.StrUtil;
import com.google.common.collect.Lists;
import info.peigen.hotpot.business.customer.core.domain.Customer;
import info.peigen.hotpot.business.customer.core.domain.CustomerLog;
import info.peigen.hotpot.business.customer.core.domain.auth.CustomerAuthentication;
import info.peigen.hotpot.business.customer.core.domain.auth.CustomerAuthenticationBase;
import info.peigen.hotpot.business.customer.core.domain.auth.CustomerAuthenticationIdentity;
import info.peigen.hotpot.business.customer.core.domain.auth.CustomerAuthenticationLog;
import info.peigen.hotpot.business.customer.core.domain.operator.CustomerOperator;
import info.peigen.hotpot.business.customer.core.repository.service.CustomerRepository;
import info.peigen.hotpot.business.customer.core.util.VerifyUtil;
import info.peigen.hotpot.business.customer.facade.enums.CustomerAction;
import info.peigen.hotpot.business.customer.facade.enums.CustomerStatus;
import info.peigen.hotpot.business.customer.facade.enums.auth.CustomerAuditOpinion;
import info.peigen.hotpot.business.customer.facade.enums.auth.CustomerCertRole;
import info.peigen.hotpot.business.customer.facade.enums.auth.CustomerCertStatus;
import info.peigen.hotpot.business.customer.facade.order.authentication.*;
import info.peigen.hotpot.business.customer.facade.order.login.CustomerLoginOrder;
import info.peigen.hotpot.business.customer.facade.order.register.CustomerForgotPasswordOrder;
import info.peigen.hotpot.business.customer.facade.order.update.CustomerUpdateOrder;
import info.peigen.hotpot.common.core.order.Order;
import info.peigen.hotpot.common.core.util.PasswordUtils;
import org.noear.solon.annotation.Inject;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.function.BiConsumer;

/**
 * <b>(CustomerDomainAction)</b>
 *
 * @author Peigen
 * @version 1.0.0
 * @since 2021/8/5
 */
@SuppressWarnings("unused")
public class CustomerDomainAction {
    @Inject
    private static CustomerRepository customerRepository;

    public static void updateEmail(Customer customer, Order order) {
        CustomerUpdateOrder customerUpdateOrder = (CustomerUpdateOrder) order;
        String              email               = customerUpdateOrder.getEmail();

        Assert.isTrue(Validator.isEmail(email), "邮箱格式不正确");

        customer.getOperators().forEach(uo ->
                Assert.isFalse(StrUtil.equals(uo.getBaseInfo().getEmail(), email), "该邮箱已存在, 不能作为新的邮箱"));

        customer.getCustomerBase().setEmail(email);

        CustomerOperator customerOperator = getCustomerOperator(customer, customerUpdateOrder.getOperatorId());
        customerOperator.getBaseInfo().setEmail(email);
        customerOperator.setUpdateTime(DateUtil.date());
    }

    public static void updateMobile(Customer customer, Order order) {
        CustomerUpdateOrder customerUpdateOrder = (CustomerUpdateOrder) order;
        String              mobile              = customerUpdateOrder.getMobile();

        Assert.isTrue(Validator.isMobile(mobile), "手机号码格式不正确");

        customer.getCustomerBase().setMobile(mobile);

        CustomerOperator customerOperator = getCustomerOperator(customer, customerUpdateOrder.getOperatorId());
        customerOperator.getBaseInfo().setMobile(mobile);
        customerOperator.setLoginName(mobile);
        customerOperator.setUpdateTime(DateUtil.date());
    }

    public static void updateVerify(Customer customer, Order order) {
        CustomerUpdateOrder customerUpdateOrder = (CustomerUpdateOrder) order;
        switch (CustomerAction.getByCode(customerUpdateOrder.getProductCode())) {
            case updateEmail:
            case updateMobile:
            case updatePayPassword:
                CustomerDomainAction.updateVerify(customer, order, (updateOrder, customerOperator) -> {
                    Assert.notNull(customerOperator.getPayPassword(), "当前您未设置交易密码");
                    Assert.isTrue(passwordEquals(customerUpdateOrder.getLoginPassword(), customerOperator.getPayPassword(), customerOperator.getSalt()), "当前交易密码不正确");
                });
                break;
            case updateLoginPassword:
                CustomerDomainAction.updateVerify(customer, order, (updateOrder, customerOperator) ->
                        Assert.isTrue(passwordEquals(updateOrder.getLoginPassword(), customerOperator.getLoginPassword(), customerOperator.getSalt()), "当前登录密码不正确!"));
                break;
            default:
                break;
        }
    }

    public static void updateVerify(Customer customer, Order order, BiConsumer<CustomerUpdateOrder, CustomerOperator> consumer) {
        CustomerUpdateOrder customerUpdateOrder = (CustomerUpdateOrder) order;

        CustomerOperator customerOperator = getCustomerOperator(customer, customerUpdateOrder.getOperatorId());

        consumer.accept(customerUpdateOrder, customerOperator);
    }

    public static CustomerOperator getCustomerOperator(Customer customer, String operatorId) {
        return customer.getOperators()
                .stream()
                .filter(customerOperator -> StrUtil.equals(customerOperator.getOperatorId(), operatorId))
                .findFirst()
                .orElseThrow(() -> new IllegalArgumentException("客户不存在!"));
    }

    public static boolean passwordEquals(String unencryptedPassword, String encryptedPassword, String salt) {
        return StrUtil.equals(encryptedPassword, PasswordUtils.generatePwdEncrypt(unencryptedPassword, salt));
    }

    public static void updatePayPassword(Customer customer, Order order) {
        updateVerify(customer, order, (customerUpdateOrder, customerOperator) -> {
            String salt        = customerOperator.getSalt();
            String newPassword = customerUpdateOrder.getNewLoginPassword();

            if (CustomerAction.getByCode(customerUpdateOrder.getProductCode()) == CustomerAction.updatePayPassword) {
                Assert.notNull(customerOperator.getPayPassword(), "当前您未设置交易密码");
                Assert.isTrue(passwordEquals(customerUpdateOrder.getLoginPassword(), customerOperator.getPayPassword(), customerOperator.getSalt()), "当前交易密码不正确");
            }

            Assert.isTrue(StrUtil.equals(customerUpdateOrder.getNewLoginPassword(), customerUpdateOrder.getNewLoginPasswordConfirm()), "两次输入的密码不一致!");
            Assert.isTrue(VerifyUtil.checkPasswordFormat(newPassword), "密码格式错误");
            Assert.isFalse(passwordEquals(newPassword, customerOperator.getLoginPassword(), customerOperator.getSalt()), "新交易密码不能与登录密码相同!");

            // 用登录密码的盐作为交易密码的盐生成交易密码
            String password = PasswordUtils.generatePwdEncrypt(customerUpdateOrder.getNewLoginPassword(), salt);
            customer.getMasterOperator().setPayPassword(password).setSalt(salt);

            //保存交易密码
            customer.getMasterOperator().setUpdateTime(DateUtil.date());
            customer.getMasterOperator().getActiveInfo().setPayPasswordLastModifyTime(new Date());
        });
    }

    public static void updateLoginPassword(Customer customer, Order order) {
        updateVerify(customer, order, (customerUpdateOrder, customerOperator) -> {
            // 根据盐值计算密码
            String salt        = customerOperator.getSalt();
            String newPassword = customerUpdateOrder.getNewLoginPassword();

            if (CustomerAction.getByCode(customerUpdateOrder.getProductCode()) == CustomerAction.updateLoginPassword) {
                Assert.notNull(customerOperator.getLoginPassword(), "当前未设置登录密码");
                Assert.isTrue(passwordEquals(customerUpdateOrder.getLoginPassword(), customerOperator.getLoginPassword(), salt), "当前登录密码不正确!");
            }

            Assert.isTrue(StrUtil.equals(newPassword, customerUpdateOrder.getNewLoginPasswordConfirm()), "两次输入的密码不一致!");
            Assert.isTrue(VerifyUtil.checkPasswordFormat(newPassword), "密码格式错误");
            Assert.isFalse(passwordEquals(newPassword, customerOperator.getPayPassword(), customerOperator.getSalt()), "新登录密码不能与交易密码相同!");

            // 生成密码
            String loginPassword = PasswordUtils.generatePwdEncrypt(customerUpdateOrder.getNewLoginPassword(), salt);
            customer.getMasterOperator().setLoginPassword(loginPassword).setSalt(salt);
            customer.getMasterOperator().setUpdateTime(DateUtil.date());
            customer.getMasterOperator().getActiveInfo().setLoginPasswordLastModifyTime(new Date());
        });
    }

    public static void setUpPassword(Customer customer, Order order, List<CustomerLog> forthHeadList) {
        CustomerForgotPasswordOrder forgotOrder = (CustomerForgotPasswordOrder) order;
        Assert.isTrue(StrUtil.equals(forgotOrder.getLoginPassword(), forgotOrder.getLoginPasswordConfirm()), "两次输入的密码不一致!");
        CustomerOperator customerOperator = customer.getOperators()
                .stream()
                .filter(operator -> StrUtil.equals(operator.getLoginName(), forgotOrder.getMobile()))
                .findFirst()
                .orElseThrow(() -> new IllegalArgumentException("客户不存在!"));

        Assert.isFalse(passwordEquals(forgotOrder.getLoginPassword(), customerOperator.getPayPassword(), customerOperator.getSalt()), "新登录密码不能与交易密码相同!");

        for (CustomerLog list : forthHeadList) {
            Assert.isFalse(passwordEquals(forgotOrder.getLoginPassword(), list.getPassword(), customerOperator.getSalt()), "修改密码不能于前4次相同!");
        }
        String salt = customerOperator.getSalt();

        // 生成密码
        String loginPassword = PasswordUtils.generatePwdEncrypt(forgotOrder.getLoginPassword(), salt);
        customer.getMasterOperator().setLoginPassword(loginPassword).setSalt(salt);
        customer.getMasterOperator().getActiveInfo().setLoginPasswordLastModifyTime(new Date());
    }

    public static void login(Customer customer, Order order) {
        CustomerLoginOrder loginOrder = (CustomerLoginOrder) order;
        String             loginName  = loginOrder.getLoginName();

        // 1. 根据登录名找到当前登录操作员
        CustomerOperator customerOperator = customer.getOperators().stream()
                .filter(operator -> StrUtil.equals(operator.getLoginName(), loginName)
                        || StrUtil.equals(operator.getBaseInfo().getEmail(), loginName)
                        || StrUtil.equals(operator.getBaseInfo().getMobile(), loginName))
                .findFirst().orElse(null);
        Assert.notNull(customerOperator, "客户名或密码错误!");
    }

    public static void freeze(Customer customer, Order order) {

    }

    public static void delete(Customer customer, Order order) {

    }

    public static void applyAuthentication(Customer customer, Order order) {
        CustomerApplyAuthenticationOrder customerApplyAuthenticationOrder = (CustomerApplyAuthenticationOrder) order;

        // 客户基本信息
        customer.setCustomerBase(customer.getCustomerBase().setAddress(customerApplyAuthenticationOrder.getAddress().getAddress()));

        // 成员信息
        List<CustomerApplyAuthenticationIdentity> identities   = customerApplyAuthenticationOrder.getIdentities();
        List<CustomerAuthenticationIdentity>      identityList = new ArrayList<>();
        if (!CollUtil.isEmpty(identities)) {
            identities.forEach(i -> {
                CustomerAuthenticationIdentity customerAuthenticationIdentity = new CustomerAuthenticationIdentity();
                BeanUtil.copyProperties(i, customerAuthenticationIdentity);
                customerAuthenticationIdentity.setCustomerId(customer.getCustomerId());
                identityList.add(customerAuthenticationIdentity);
            });
        }

        // 实名认证基础信息
        CustomerAuthenticationBase customerAuthenticationBase = customer.getAuthentication().getCustomerAuthenticationBase();
        BeanUtil.copyProperties(customerApplyAuthenticationOrder, customerAuthenticationBase);

        // 实名状态信息
        CustomerAuthentication customerAuthentication = customer.getAuthentication();
        customerAuthentication.setIdentities(identityList);
        customerAuthentication.setCustomerCertType(customerApplyAuthenticationOrder.getCustomerCertType());
        customerAuthentication.setCustomerCertSubject(customerApplyAuthenticationOrder.getCustomerCertSubject());
        customerAuthentication.setCustomerCertStatus(CustomerCertStatus.CERT_AUDITING);
        customerAuthentication.setCustomerAuthenticationBase(customerAuthenticationBase);
        customer.setAuthentication(customerAuthentication);
    }

    public static void applyPersonalAuthentication(Customer customer, Order order) {
        CustomerApplyPersonalAuthenticationOrder customerApplyPersonalAuthenticationOrder = (CustomerApplyPersonalAuthenticationOrder) order;

        // 成员信息
        List<CustomerAuthenticationIdentity> identityList                   = new ArrayList<>();
        CustomerAuthenticationIdentity       customerAuthenticationIdentity = new CustomerAuthenticationIdentity();
        BeanUtil.copyProperties(customerApplyPersonalAuthenticationOrder, customerAuthenticationIdentity);
        identityList.add(customerAuthenticationIdentity);
        // 客户基本信息
        customer.setCustomerBase(customer.getCustomerBase().setAddress(customerApplyPersonalAuthenticationOrder.getAddress().getAddress()));
        // 申请表放基础信息里
        CustomerAuthenticationBase customerAuthenticationBase = customer.getAuthentication().getCustomerAuthenticationBase()
                .setHoldingAccountApplyingImage(customerApplyPersonalAuthenticationOrder.getHoldingAccountApplyingImage())
                .setHoldingAccountApplyingOriginImage(customerApplyPersonalAuthenticationOrder.getHoldingAccountApplyingOriginImage())
                .setEnterpriseName(customerApplyPersonalAuthenticationOrder.getName());
        // 实名状态信息
        CustomerAuthentication customerAuthentication = customer.getAuthentication();
        customerAuthentication.setIdentities(identityList);
        customerAuthentication.setCustomerCertType(customerApplyPersonalAuthenticationOrder.getCustomerCertType());
        customerAuthentication.setCustomerCertSubject(customerApplyPersonalAuthenticationOrder.getCustomerCertSubject());
        customerAuthentication.setCustomerCertStatus(CustomerCertStatus.CERT_AUDITING);
        customerAuthentication.setCustomerAuthenticationBase(customerAuthenticationBase);
        customer.setAuthentication(customerAuthentication);
    }

    public static void updateBusinessAddress(Customer customer, Order order) {
        CustomerUpdateBusinessAddressOrder customerUpdateBusinessAddressOrder = (CustomerUpdateBusinessAddressOrder) order;
        // 实名认证基础信息
        CustomerAuthenticationBase customerAuthenticationBase = customer.getAuthentication().getCustomerAuthenticationBase();
        BeanUtil.copyProperties(customerUpdateBusinessAddressOrder, customerAuthenticationBase);
        // 实名状态信息
        CustomerAuthentication customerAuthentication = customer.getAuthentication();
        customerAuthentication.setCustomerAuthenticationBase(customerAuthenticationBase);
        customer.setAuthentication(customerAuthentication);

    }

    public static void updateControlPeople(Customer customer, Order order) {
        BopsCustomerUpdateControlPeopleOrder updateControlPeopleOrder = (BopsCustomerUpdateControlPeopleOrder) order;
        // 提交成员信息
        List<CustomerApplyAuthenticationIdentity> identities = updateControlPeopleOrder.getIdentities();
        // 实名状态信息
        CustomerAuthentication customerAuthentication = customer.getAuthentication();
        // 已有成员信息
        List<CustomerAuthenticationIdentity> existIdentities = customerAuthentication.getIdentities();
        List<CustomerAuthenticationIdentity> identityList    = new ArrayList<>();
        if (!CollUtil.isEmpty(existIdentities)) {
            existIdentities.forEach(identity -> {
                if (!identity.getCustomerCertRole().isInList(CustomerCertRole.Control_People)) {
                    CustomerAuthenticationIdentity customerAuthenticationIdentity = new CustomerAuthenticationIdentity();
                    BeanUtil.copyProperties(identity, customerAuthenticationIdentity);
                    identityList.add(customerAuthenticationIdentity);
                }
            });
        }

        if (!CollUtil.isEmpty(identities)) {
            identities.forEach(i -> {
                CustomerAuthenticationIdentity customerAuthenticationIdentity = new CustomerAuthenticationIdentity();
                BeanUtil.copyProperties(i, customerAuthenticationIdentity);
                customerAuthenticationIdentity.setCustomerId(customer.getCustomerId());
                identityList.add(customerAuthenticationIdentity);
            });
        }


        customerAuthentication.setIdentities(identityList);
        customer.setAuthentication(customerAuthentication);
    }

    public static void auditAuthentication(Customer customer, Order order) {
        CustomerAuditAuthenticationOrder customerAuditAuthenticationOrde = (CustomerAuditAuthenticationOrder) order;

        CustomerCertStatus customerCertStatus;
        if (CustomerAuditOpinion.PASS.isInList(customerAuditAuthenticationOrde.getAuditOpinion())) {
            customerCertStatus = CustomerCertStatus.CERT_PASS;
            customer.setStatus(CustomerStatus.Cert_Pass);
        } else {
            customerCertStatus = CustomerCertStatus.CERT_REFUSE;
        }

        // 实名前状态
        CustomerCertStatus preCustomerCertStatus = customer.getAuthentication().getCustomerCertStatus();

        // 更新实名状态
        customer.getAuthentication().setCustomerCertStatus(customerCertStatus);

        // 构造审核记录
        customer.getAuthentication().setLogs(Lists.newArrayList(CustomerAuthenticationLog.builder()
                .memo(customerAuditAuthenticationOrde.getMemo())
                .bopsAuditTime(new Date())
                .bopsOperatorId(customerAuditAuthenticationOrde.getBopsOperatorId())
                .bopsOperatorName(customerAuditAuthenticationOrde.getBopsOperatorName())
                .customerCertSubject(customer.getAuthentication().getCustomerCertSubject())
                .preStatus(preCustomerCertStatus)
                .postStatus(customerCertStatus)
                .customerId(customerAuditAuthenticationOrde.getCustomerId())
                .gid(customerAuditAuthenticationOrde.getGid())
                .enterpriseInfo(customer.getAuthentication().getCustomerAuthenticationBase())
                .build()));
    }

}